/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package MyDatabaseHandler;

import java.io.File;
import java.util.ArrayList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import MyDataContainer.*;
import MyDataType.*;
/**
 *
 * @author Welcome
 */
public class XMLHandler {
    
    //<editor-fold defaultstate="collapsed" desc="1/Cac thuoc tinh">
    private File xmlFile;
    private DocumentBuilderFactory dbf;
    private DocumentBuilder db;
    private Document doc;
    private String pathFile=".";
    //</editor-fold>
    
    //<editor-fold defaultstate="collapsed" desc="2/Cac phuong thuc khoi tao">
    public XMLHandler(String pathFile) {
        this.pathFile = pathFile;
        initialize();
    }
    public XMLHandler()
    {
        xmlFile=null;
        dbf=null;
        db=null;
        doc=null;
        
    }
    
    private void initialize()
    {
        try {
            File xmlFile = new File(pathFile);
            if(xmlFile.exists())
            {
                dbf = DocumentBuilderFactory.newInstance();
                db = dbf.newDocumentBuilder();
                doc = db.parse(xmlFile);
                doc.getDocumentElement().normalize();
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
    //</editor-fold>
    
    //<editor-fold defaultstate="collapsed" desc="3/Getter/Setter">
    
    public void setPathFile(String pathFile) {
        this.pathFile = pathFile;
    }
    
    //</editor-fold>
    
    //<editor-fold defaultstate="collapsed" desc="4/Read database to memory">
    
    /*
     * Tim tat ca cac node children
     * @param parent : node cha
     * @param tagName : ten node children
     */
    private NodeList findChildren(Element parent, String tagName)
    {
        NodeList tempNodeList = parent.getElementsByTagName(tagName);
        return tempNodeList;
    }
    
    /*
     * Lay ten database trong file xml
     */
    public String getDatabaseName()
    {
        Element rootEle = doc.getDocumentElement();
        String temp="";
        temp = rootEle.getAttribute("dbName");
        return temp;
    }
    
    /*
     * Dua du lieu trong cac node table vao cac bang table
     * @param tables : cac bang trong database
     */
    public void SetDataIntoTable(ArrayList<MyTable> tables) {
        NodeList listTables = findChildren(doc.getDocumentElement(), "table");
        
        for(int i=0;i<listTables.getLength();i++)
        {
            Node tempnNode = listTables.item(i);
            
            if(tempnNode.getNodeType()==Element.ELEMENT_NODE)
            {
                Element tableElement = (Element)tempnNode;      //Day la mot table
                MyTable tempTable = ProcessForTableOnRead(tableElement);
                
                tables.add(tempTable);
            }
        }
    }
    
    //Chuyen data co trong node tableElement vao 1 object MyDataString
    private MyTable ProcessForTableOnRead(Element tableElement)
    {
        MyTable tempTable=new MyTable();
        tempTable.setName(tableElement.getAttribute("tableName"));
        
        //Lay thong tin tieu de cac cot, cac khoa chinh
        Element columnInfoElement = (Element)findChildren(tableElement, "column").item(0);
        
        MyDataString tempData=GetAttributeContents(columnInfoElement, "columnTitles");
        int numberColumn = tempData.getSize();
        tempTable.setColumnTitles(tempData);
        MyDataString dataTypes = new MyDataString();
        dataTypes = GetAttributeContents(columnInfoElement, "dataType");
        tempTable.setDataTypeList(dataTypes);
        tempData=GetAttributeContents(columnInfoElement, "primaryKeys");
        tempTable.setPrimaryKeys(tempData);
        
        tempData = GetAttributeContents(columnInfoElement, "foreignKeys");
        ArrayList<MyForeignKey> listFKeys = processForForeignKeys(tempData);
        tempTable.setForeignKeys(listFKeys);

        NodeList rowsList=findChildren(tableElement, "row");
        for(int i=0; i<rowsList.getLength();i++)
        {
            Node tempNode = rowsList.item(i);
            if(tempNode.getNodeType()==Element.ELEMENT_NODE)
            {
                Element rowElement = (Element)tempNode;
                MyDataSet tempDataSet=ProcessForRows(rowElement,numberColumn,dataTypes);
                tempTable.addContent(tempDataSet);
            }
            //tempTable.addContent(tempDataSet);
        }
        
        return tempTable;
        
    }
    
    /*
     * Lay du lieu co trong Attribute, moi du lieu cach nhau boi dau ","
     * @param ele : Element chua attribute
     * @param attName : ten Attribute
     */
    private MyDataString GetAttributeContents(Element ele,String attName)
    {
        MyDataString resultMyDataString = new MyDataString();
        String[] tempStrings = ele.getAttribute(attName).split(",");
        for(int i=0;i<tempStrings.length;i++)
        {
            resultMyDataString.addContent(tempStrings[i]);
        }
        
        return resultMyDataString;
    }
    
    private MyDataSet ProcessForRows(Element rowElement,int numberColumn,MyDataString dataTypes) 
    {
        MyDataSet tempRow=new MyDataSet();
        for(int i=0; i<numberColumn;i++)
        {
            String type = dataTypes.getAt(i);
            String tempString = "c" + String.valueOf(i);
            String dataColumn = rowElement.getAttribute(tempString);
            MyData tempMyData=null;
            
            if(type.equals("int"))
            {
                tempMyData = new MyInt(dataColumn);
            }
            else
            {
                if (type.equals("string"))
                    tempMyData = new MyString(dataColumn);
            }
                
            tempRow.addData(tempMyData);
        }
        
        return tempRow;
    }
    
    private ArrayList<MyForeignKey> processForForeignKeys(MyDataString Fkeys) 
    {
        ArrayList<MyForeignKey> resultKeys = new ArrayList<MyForeignKey>();
        for(int i=0;i<Fkeys.getSize();i++)
        {
            String[] tempStrings=Fkeys.getAt(i).split("\\.");
            MyForeignKey tempKey = new MyForeignKey();
            tempKey.setFKey(tempStrings);
            resultKeys.add(tempKey);
        }
        return resultKeys;
    }

    //</editor-fold>

    //<editor-fold defaultstate="collapsed" desc="5/Write to file">
    
    private Element createDatabaseElementOnWrite(DatabaseHandler dbHandler)
    {
            
            Element databaseElement=doc.createElement("database");
            databaseElement.setAttribute("dbName", dbHandler.getDatabaseName());
            databaseElement.setAttribute("numberTable", dbHandler.getNumberTablesByString());
            
            //table elements
            ArrayList<MyTable> tempTables=new ArrayList<MyTable>(dbHandler.getTables());
            for(int i=0;i<tempTables.size();i++)
            {
                MyTable myTable= tempTables.get(i);
                Element tableElement = createTableElementOnWrite(myTable);
                databaseElement.appendChild(tableElement);
            }
        
        return databaseElement;
    }
    
    //Viết 1 element bất kỳ thành file XML
    private void writeElementToXMLFile(String desPathFile,Element rootElement)
    {
        try {
            
            doc=rootElement.getOwnerDocument();
            doc.removeChild(doc.getDocumentElement());
            doc.appendChild(rootElement);
           
            //writerDoc.appendChild(doc.importNode(rootElement, true));
            //write content into XML file
            TransformerFactory transformerFactory=TransformerFactory.newInstance();
            Transformer transformer = transformerFactory.newTransformer();
            DOMSource source = new DOMSource(doc);
            StreamResult result = new StreamResult(new File(desPathFile));
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            transformer.transform(source, result);
            System.out.println("Saved!");
            
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
    
    public void writeTableToXMLFile(String desPathFile, MyTable myTable)
    {
        Element rootElement = createTableElementOnWrite(myTable);
        writeElementToXMLFile(desPathFile, rootElement);
    }
    
    public void writeDatabaseToXMLFile(String desPathFile, DatabaseHandler dbHandler) 
    {
        Element rootElement = createDatabaseElementOnWrite(dbHandler);
        writeElementToXMLFile(desPathFile, rootElement);
    }
        
    //Chuyển data trong object MyTable thành 1 element
    private Element createTableElementOnWrite(MyTable myTable)
    {
                
                Element tableElement=doc.createElement("table");
                String tableName = myTable.getName();
                tableElement.setAttribute("tableName", tableName);
                
                //create columnInfo Element to insert into table Element
                Element columnInfoElement=doc.createElement("column");
                String columnTitles = joinStringListToString(myTable.getColumnTitles());
                String primaryKeys = joinStringListToString(myTable.getPrimaryKeys());
                String dataType=joinStringListToString(myTable.getDataTypeList());
                columnInfoElement.setAttribute("primaryKeys", primaryKeys);
                columnInfoElement.setAttribute("columnTitles", columnTitles);
                columnInfoElement.setAttribute("dataType", dataType);
                ArrayList<MyForeignKey> foreignKeys = new  ArrayList<MyForeignKey>(myTable.getForeignKeys());
                MyDataString fKeys = processForForeignKeysOnWrite(foreignKeys);
                String fkString = joinStringListToString(fKeys);
                columnInfoElement.setAttribute("foreignKeys", fkString);
                //Add columnInfo Element to table
                tableElement.appendChild(columnInfoElement);
                
                //create rows Element to insert into table Element
                ArrayList<MyDataSet> myRowDatas = myTable.getRowContents();
                for(int j=0;j<myRowDatas.size();j++)
                {
                    MyDataSet singleRowData = myRowDatas.get(j);
                    Element rowElement = doc.createElement("row");
                    for(int k=0; k<singleRowData.getSize();k++)
                    {
                        rowElement.setAttribute("c"+String.valueOf(k), singleRowData.getDataAt(k).getContent());
                    }
                    tableElement.appendChild(rowElement);
                }
        return tableElement;
    }
    
    public String joinStringListToString(ArrayList<String> stringList)
    {
        String result ="";
        for(int i=0;i<stringList.size(); i++)
        {
            result = result+stringList.get(i)+",";
        }
        if(result.length()>0)
        result = result.substring(0, result.length()-1);
        return result;
    }
    public String joinStringListToString(MyDataString stringList)
    {
        ArrayList<String> tempList = stringList.getData();
        return joinStringListToString(tempList);
    }
    
    private MyDataString processForForeignKeysOnWrite(ArrayList<MyForeignKey> foreignKeys) {
        MyDataString result=new MyDataString();
        for(int i=0; i<foreignKeys.size();i++)
        {
            MyForeignKey tempfk = foreignKeys.get(i);
            String tempString=tempfk.getHostTable()+"."+tempfk.getHostField()+"."+tempfk.getDesTable()+"."+tempfk.getDesField();
            result.addContent(tempString);
        }
        return result;
    }
    
    //</editor-fold>

}
